<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 1. forEach
        // forEach() 方法对数组的每个元素执行一次提供的函数。
        // 语法：array.forEach(function(currentValue, index, arr), thisValue)
        // 参数：
        // currentValue: 数组中正在处理的当前元素。
        // index(可选): 数组中正在处理的当前元素的索引。
        // arr(可选): forEach() 方法正在操作的数组。
        // thisValue(可选): 执行回调时使用的 "this" 值。
        // 返回值：undefined
        // 注意：forEach() 对于空数组是不会执行回调函数的。
        // 示例：
        const array1 = ['a', 'b', 'c'];
        array1.forEach((element,index) => console.log(element,index)); // a 0 b 1 c 2

        Array.prototype.forEach2 = function (callback, thisArg) {
            if (this == null) {
                throw new TypeError('this is null or not defined');
            }
            if (typeof callback !== 'function') {
                throw new TypeError(callback + ' is not a function');
            }
            const O = Object(this);
            const len = O.length >>> 0;
            let k = 0;
            while (k < len) {
                if (k in O) {
                    callback.call(thisArg, O[k], k, O);
                }
                k++;
            }
        }


        // 2. map
        // map() 方法创建一个新数组，其结果是该数组中的每个元素是调用一次提供的函数后的返回值。
        // 语法：array.map(function(currentValue, index, arr), thisValue)
        // 参数：
        // currentValue: 数组中正在处理的当前元素。
        // index(可选): 数组中正在处理的当前元素的索引。
        // arr(可选): map() 方法正在操作的数组。
        // thisValue(可选): 执行回调时使用的 "this" 值。
        // 返回值：一个新数组，每个元素都是回调函数的结果。
        // 示例：
        const array2 = [1, 4, 9, 16];
        const mapArray = array2.map(x => x * 2); // [2, 8, 18, 32]

        Array.prototype.map2 = function (callback, thisArg) {
            if (this==null) {
                throw new TypeError('this is null or not defined');
            }
            if (typeof callback !== 'function') {
                throw new TypeError(callback + ' is not a function');
            }
            const O = Object(this);
            const len = O.length >>> 0;
            let k = 0;
            let result = [];
            while (k < len) {
                if (k in O) {
                    result[k] = callback.call(thisArg, O[k], k, O);
                }
                k++;
            }
            return result;
        }

        // 3. filter
        // filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
        // 语法：array.filter(function(currentValue, index, arr), thisValue)
        // 参数：
        // currentValue: 数组中正在处理的当前元素。
        // index(可选): 数组中正在处理的当前元素的索引。
        // arr(可选): filter() 方法正在操作的数组。
        // thisValue(可选): 执行回调时使用的 "this" 值。
        // 返回值：一个新的、由通过测试的元素组成的数组，如果没有任何数组元素通过测试，则返回空数组。
        // 示例：
        const array3 = [5, 12, 8, 130, 44];
        const filterArray = array3.filter(x => x > 10); // [12, 130, 44]

        Array.prototype.filter2 = function(callback,thisArg){
            if(this == null) {
                throw new TypeError('this is null or not defined');
            }
            if(typeof callback !== 'function') {
                throw new TypeError(callback + ' is not a function');
            }
            const O = Object(this);
            const len = O.length >>> 0;
            let k = 0;
            let result = [];
            while(k < len) {
                if(k in O) {
                    if(callback.call(thisArg, O[k], k, O)) {
                        result.push(O[k]);
                    }
                }
                k++;
            }
            return result;
        }

        // 4. reduce
        // reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行)，将其结果汇总为单个返回值。
        // 语法：array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
        // 参数：
        // total: 必需。初始值, 或者计算结束后的返回值。
        // currentValue: 必需。当前元素
        // currentIndex(可选): 数组中正在处理的当前元素的索引。 如果提供了initialValue，则起始索引号为0，否则从索引1起始。
        // arr(可选): 调用reduce()的数组
        // initialValue(可选): 作为第一次调用 callback函数时第一个参数的值。 如果没有提供初始值，则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。
        // 返回值：函数累计处理的结果
        // 示例：
        const array4 = [1, 2, 3, 4];
        const reduceArray = array4.reduce((total, currentValue) => total + currentValue, 0); // 10

        Array.prototype.reduce2 = function(callback, initialValue) {
            if (this == null) {
                throw new TypeError('this is null or not defined');
            }
            if (typeof callback !== 'function') {
                throw new TypeError(callback + ' is not a function');
            }
            const O = Object(this);
            const len = O.length >>> 0;
            let k = 0, acc
            if (arguments.length > 1) {
                acc = initialValue;
            }else{
                while (k < len && !(k in O)) {
                    k++;
                }
                if (k >= len) {
                    throw new TypeError('Reduce of empty array with no initial value');
                }
                acc = O[k++];
            }
            while (k < len) {
                if (k in O) {
                    acc = callback(acc, O[k], k, O);
                }
                k++;
            }
            return acc;
        }


        // 5. slice
        // slice() 方法返回一个新的数组对象，这一对象是一个由 begin 和 end 决定的原数组的浅拷贝（包括 begin，不包括end）。原始数组不会被改变。
        // 语法：array.slice(begin, end)
        // 参数：
        // begin(可选): 开始位置（从0开始）
        // end(可选): 结束位置（不包括end）
        // 返回值：返回一个新的数组对象
        // 示例：
        const array5 = [1, 2, 3, 4, 5];
        const sliceArray = array5.slice(1, 3); // [2, 3]

        // 6. splice
        // splice() 方法通过删除现有元素和/或添加新元素来更改一个数组的内容。
        // 语法：array.splice(start, deleteCount, item1, item2, ...)
        // 参数：
        // start: 必需。指定修改的开始位置（从0计数）。如果超出了数组的长度，则从数组末尾开始添加内容；如果是负值，则表示从数组末位开始的第几位（从-1计数，这意味着-n是倒数第n个位置）。
        // deleteCount(可选): 必需。整数，表示要移除的数组元素个数。如果 deleteCount 大于 start 之后的元素的总数，则从 start 后面的元素都将被删除（含第 start 位）。如果 deleteCount 是 0 或者负数，则不移除元素。这种情况下，至少应添加一个新元素。
        // item1, item2, ... (可选): 要添加进数组的元素, 从 start 位置开始。如果不指定，则 splice() 将只删除数组元素。
        // 返回值：由被删除的元素组成的一个数组。如果只删除了一个元素，则返回只包含一个元素的数组。如果没有删除元素，则返回空数组。
        // 示例：
        const array6 = [1, 2, 3, 4, 5];
        const spliceArray = array6.splice(1, 2, 'a', 'b');
        console.log(array6); // [1, "a", "b", 4, 5]

        // 7. some
        // some() 方法测试数组中的某些元素是否通过了由提供的函数实现的测试。
        // 语法：array.some(callback(element[, index[, array]])[, thisArg])
        // 参数：
        // callback: 用来测试每个元素的函数，接受三个参数：
        // element: 数组中当前处理的元素。
        // index(可选): 数组中当前处理的元素的索引。
        // array(可选): 调用 some() 方法的数组。
        // thisArg(可选): 执行 callback 时使用的 this 值。
        // 返回值：如果数组中的至少一个元素满足测试函数，则返回 true，否则返回 false。
        // 示例：
        const array7 = [1, 2, 3, 4, 5];
        const someResult = array7.some((element, index, array) => {
            return element > 3;
        })
        console.log(someResult); // true

        Array.prototype.some2 = function (callback,thisArg) {
            if (this == null) {
                throw new TypeError('this is null or not defined');
            }
            if (typeof callback !== 'function') {
                throw new TypeError(callback + ' is not a function');
            }
            const O = Object(this);
            const len = O.length >>> 0;
            let k = 0;
            while (k < len) {
                if (k in O && callback.call(thisArg, O[k], k, O)) {
                    return true;
                }
                k++;
            }
            return false;
        }
    </script>
</body>
</html>